package parser;
import java.io.*;

public class DisassemblerWriter extends Saver {
    
    DisassemblerWriter(String name) {
        super(name);   
        out = System.out;
    }
    
    DisassemblerWriter(String name, PrintStream output) {
        super(name);   
        this.out = output;   
    }
    
    PrintStream out;
    
    String[] names;
    
    public void close() throws IOException {
        super.close();   
        disassemble();
    }
    
    int pointer;

    void disassemble() {
        out.println("Version " + ((int)buf[0]));
        pointer = 1;
        writeNameTable();
        writeConstantTable();
        int count = buf[pointer++]; 
        out.println("" + count + " functions"); 
        for (int i = 0; i < count; i++) {
            writeFunction();   
        }
        count = buf[pointer++]; 
        out.println("" + count + " classes"); 
        for (int i = 0; i < count; i++) {
            writeClass();   
        }
        out.println("Script:");
        writeCode();
        out.println("" + this.count + " codes (" + this.count * 2 + " bytes)"); 
    }

    void writeNameTable() {
        int count = buf[pointer++];   
        names = new String[count];
        out.println("" + count + " names"); 
        for (int i = 0; i < count; i++) {
            names[i] = readString();
            out.println("" + i + ": " + names[i]);
        }
    }

    String readString() {
        int count = buf[pointer++];   
        char[] c = new char[count];
        for (int i = 0; i < count/2; i++) {
            c[i*2] = (char)(buf[pointer] >>> 8);
            c[i*2 + 1] = (char)(buf[pointer++] & 0xff);
        } 
        if ((count & 1) != 0) {
            c[count -1] = (char)(buf[pointer++] >>> 8);
        }
        return new String(c);
    }

    void writeConstantTable() {
        int count = buf[pointer++];   
        out.println("" + count + " constants"); 
        for (int i = 0; i < count; i++) {
            int size =  buf[pointer++];
            out.print("size: " + size);
            for (int j = 0; j < (size + 1)/2; j++) {
                out.print(" " + (int)buf[pointer++]);
            }
            out.println();
        }
    }

    void writeName(String prefix) {
        out.flush();
        int index = (buf[pointer++] << 16) >> 16;
        if (index < 256) {
            out.println(prefix + index + " \"" + StandardNames.names[index] + "\"" );
        } else if (index < names.length + 256) {
            out.println(prefix + index + " \"" + names[index - 256] + "\"" );
        } else {
            out.println(prefix + index + " Illegal index");   
        }
       
    }   

    void writeFunction() {
        writeName("Function name: ");
        int params = buf[pointer++];
        out.println("" + params + " parameters");
        for (int i = 0; i < params; i++) {
            writeName("Type: ");   
        }
        int locals = buf[pointer++];
        out.println("" + locals + " locals");
        out.println("" + (int)buf[pointer++] + " stack");
        writeCode();
        for (int i = 0; i < locals; i++) {
            writeName("Local " + i + ": ");   
        }
    }

    void writeCode() {
        int count = buf[pointer++]; 
        for (int i = 0; i < count; i++) {
            int code = buf[pointer++]; 
            out.println(Opcodes.names[code >> 11] + " " + (((code & 0x7ff) << 21) >> 21));
        }
    }
    
    void writeClass() {
        throw new Error("Not implemented");   
    }
}


